//
// Alain Boucher - 19/03/2008
//
// Fonctions utilitaires pour la transformée de Fourier
// TP du cours de Traitement d'images
//
// Note : Les fonctions ci-dessous ne contiennent pas (volontairement)
//        de commentaires dans le code. Les seuls commentaires sont dans 
//        la facon d'utiliser les fonctions. Modifier les parametres et
//        observer les resultats pour bien comprendre le fonctionnement.
//

#include "ImageGray.h"
#include "fft2d_util.h"

using namespace Torch;


//
// Tab1D_to_Image2D
//
// Cette fonction transforme un tableau 1D en une image 2D
//
// Entrees
// tab : tab 1D de taille width*height
// improve : rehausse le contenu de l'image par une transformation logarithmique
// swap : echange les quadrants pour mettre l'origine au centre de l'image
//
// Sortie
// une image ImageGray de taille width x height
//

ImageGray *Tab1D_to_Image2D (real *tab, int width, int height, bool improve, bool swap)
{
	int size = width * height;

	real *tab2 = new real [size];
	for(int i = 0 ; i < size ; i++)
		tab2[i] = fabs(tab[i]);
	
	if (improve)
		for(int i = 0 ; i < size ; i++)
			tab2[i] = log ( 1.0 + fabs (tab2[i]) );

	real min = 0.;
	real max = 0.;
	for(int i = 0 ; i < size ; i++)
	{
		if ((tab2[i] < min) || (i==0))  min = tab2[i];
		if ((tab2[i] > max) || (i==0))  max = tab2[i];
	}
	real maxmin = max - min;

	if (swap) SwapTabImage (tab2, width, height);

        ImageGray *image_tab = new ImageGray (width, height);

	for(int i = 0 ; i < size ; i++)
	{
		real val = ((tab2[i] - min) / maxmin) * 255.;
		if (val<0.)   val = 0.;
		if (val>255.)   val = 255.;
		image_tab->pixmap[i] = (unsigned char)val;
	}

	delete[] tab2;
	return image_tab;
}


//
// SwapTabImage
//
// Echange les quadrants d'une image pour mettre l'origine au centre (sinon en (0,0))
//
// 	AB  ->  DC
// 	CD      BA
//
// tab : tab 1D de taille width*height  (tableau modifie en sortie)
//
// Note : Pour les besoins du TP, vous n'avez pas besoin d'appeler cette fonction.
//        Cette fonction est automatiquement appelee dans Tab1D_to_Image2D.
//

void SwapTabImage (real *tab, int width, int height)
{
	int width2 = width/2;
	int height2 = height/2;

	real val = 0.;
	int ind1=0, ind2=0;
	for (int j=0; j<height2; j++)
	{
		for (int i=0; i<width2; i++)
		{
			ind1 = (j*width) + i;
			ind2 = ((j+height2) * width) + i + width2;
			val = tab[ind1];
			tab[ind1] = tab[ind2];
			tab[ind2] = val;
		}
		for (int i=width2; i<width; i++)
		{
			ind1 = (j*width) + i;
			ind2 = ((j+height2) * width) + i - width2;
			val = tab[ind1];
			tab[ind1] = tab[ind2];
			tab[ind2] = val;
		}
	}

	return;
}


//
// DefinirFiltre1
//
// Definit un filtre a appliquer sur une image frequentielle (apres Transformee de Fourier)
// Ce filtre est additif (addition pixel a pixel sur les images reelle et imaginaire)
//
// Entrees
// int width, height : taille de l'image a filtrer
// float facteur : parametre du filtre : 0 < facteur < 1
//
// Note : On définit ci-dessous un filtre binaire (0 ou 1). Pour accentuer les
// effets de ce filtre (et mieux comprendre), il est suggérer de remplacer les
// 1 par la valeur maximale de l'image lors du filtrage.
//
// Sortie
// un tableau 1D de taille width*height contenant le filtre
//

real *DefinirFiltre1(int width, int height, float facteur) {
	int size = width * height;

	real *filtre = new real[size];
	for (int i = 0; i < size; i++)
		filtre[i] = 0.0;

	int facty = int(float(height / 2) * facteur);
	int factx = int(float(width / 2) * facteur);

	filtre[(facty * width) + factx] = 1.0;
	filtre[((height - facty) * width) + width - factx] = 1.0;

	return filtre;
}


//
// AppliquerFiltre1
//
// Filtrage additif du tableau 1D fft par le filtre filtre1
//
// Note : Pour accentuer le filtrage, on remplace les valeurs 1 par le maximum de l'image.
//
// En sortie, le tableau fft est modifie
//

void AppliquerFiltre1(real *fft, real *filtre1, int size) {
	real max = 0;
	int i;

	for (i = 0; i < size; i++) {
		if ((fft[i] > max) || (i == 0))
			max = fft[i];
	}
	
	for (i = 0; i < size; i++) {
		if (filtre1[i] > 0.) {
			
			fft[i] = max;
		}
	}

	return;
}



//
// DefinirFiltre2
//
// Definit un filtre a appliquer sur une image frequentielle (apres Transformee de Fourier)
// Ce filtre est multiplicatif (multiplication pixel a pixel sur les images reelle et imaginaire)
//
// Entrees
// int width, height : taille de l'image a filtrer
// float facteur : parametre du filtre : 0 < facteur < 1
// bool inverse : parametre du filtre : true | false
//
// Note : On définit ci-dessous un filtre binaire (0 ou 1). 
//
// Sortie
// un tableau 1D de taille width*height contenant le filtre
//

real *DefinirFiltre2 (int width, int height, float facteur, bool inverse)
{
	real val1 = 0.;
	real val2 = 1.;
	if (inverse)
	{
		val1 = 1.;
		val2 = 0.;
	}

	int size = width * height;
	real *filtre = new real [size];
	for (int i=0; i<size; i++) filtre[i] = val2;

	int height2 = height/2;
	int width2  = width/2;

	int radius = int(float(height2)*facteur);
	if (width2 < height2)
		radius = int(float(width2)*facteur);

	int radius2 = radius*radius;

	for (int y=0; y<=radius; y++)
		for (int x=0; x<=radius; x++)
		{
			if (((y*y) + (x*x)) <= radius2 )
			{
				filtre[(y*width) + x] = val1;
				if ((y>0) && (x>0)) filtre[((height-y)*width) + width-x] = val1;
				if (y>0)            filtre[((height-y)*width) + x] = val1;
				if (x>0)            filtre[(y*width) + width-x] = val1;
			}
		}

   return filtre;
}


//
// AppliquerFiltre2
//
// Filtrage multiplicatif du tableau 1D fft par le filtre filtre2
//
// En sortie, le tableau fft est modifie
//

void AppliquerFiltre2 (real *fft, real *filtre2, int size)
{
	for (int i=0; i<size; i++)
		if (filtre2[i] < 0.1) fft[i] = 0;

	return;
}

// fin de fft2d_util.cc



